TailsConfig.registerFormat({
  name: 'hcalendar',
  topNodeClass: 'vevent',

  simpleValueClasses: ["dtstart", "dtend", "summary", "location", "comment"
      , "description", "contact", "sequence", "priority", "dtstamp", "last-modified"
      , "created", "recurrence-id", "class", "status", "transp"],

  urlValueClasses: ["url"],

  dateValueClasses: ["dtstart", "dtend", "dtstamp"],
  
  embeddedFormatClasses: { location: 'hcard', attendee: 'hcard'
      , contact: 'hcard', organizer: 'hcard', geo: 'geo' },

  genericURLAttributes: ["url"],

  customBindings: {
    vcard: function(node, object) {
      /* A hCard that is not explicitly identified will automatically be considered the location */
      if (!this.html.isAnyClass(node, ['location', 'attendee', 'contact', 'organizer'])) {
        object.location_hcard = TailsConfig.getFormat('hcard').parseObject(node);
      }
    },
    
    rrule: function(node, object) {
      object.rrule = FormatBase.createFormat({
          simpleValueClasses: ["freq", "until"],
          pluralValueClasses: ["byday"] }).parseObject(node);
    },
    
    attach: function(node, object) {
      object.attach = {
        url: FormatBase.toURL(node),
      	type: node.getAttribute("type")
      }
    },
    
    organizer: function(node, object) {
      object.organizer = {};
      TailsConfig.getFormat('hcalendar')
          ._evalUserObject(node, object.organizer);
    },
    
    attendee: function(node, object) {
      var attendee = FormatBase.createFormat({
          simpleValueClasses: ["partstat", "role", "delegated-from", "rsvp"],
          customBindings: { value: function(node, object) {
            TailsConfig.getFormat('hcalendar')
                ._evalUserObject(node, object);
          }}}).parseObject(node);
      if (object.attendee)
        object.attendee = attendee;
      if (!object.attendees) object.attendees = [];
      object.attendees.push(attendee);
    },
    
    category: TailsConfig.getFormat('hcard').customBindings.category,
    uid: TailsConfig.getFormat('hcard').customBindings.uid
  },
  
  _getLabel: function(object) {
    if (object.summary) return object.summary;
    if (object.location_hcard) return object.location_hcard.generic.label;
  },

  _getDescription: function(object) {
    if (object.dtstart_date) {
      var s = '';
      if (object.dtstart_date.getFullYear() < 0) {
        s = FormatBase.prettyDate(object.dtstart_date, "%H:%M");
      } else {
        s = FormatBase.prettyDate(object.dtstart_date);
      }
      if (object.dtend_date) {
        s += " - ";
        if (object.dtend_date.getFullYear() < 0) {
          s += FormatBase.prettyDate(object.dtend_date, "%H:%M");
        } else {
          s += FormatBase.prettyDate(object.dtend_date);
        }
      }
      return s;
    }
    if (object.location_hcard) {
      if (object.location_hcard.label) {
        return object.location_hcard.generic.label;
      } else if (object.location_hcard.locality || object.location_hcard.region) {
        var s = object.location_hcard.locality ? object.location_hcard.locality : "";
        if (object.location_hcard.region) {
          if (s != "") s += ", ";
          s += object.location_hcard.region;
        }
        return s;
      }
    }
    if (object.location) {
      return object.location;
    } else {
      return object.description;
    }
  },
  
  objectMethods: {
    eventIntervalString: function() {
      s = '';
      s += ((this.dtstart_date)? FormatBase.prettyDate(this.dtstart_date, "%B %d, %Y %H:%M") : this.dtstart);
      s += ' - ';
      s += ((this.dtend_date)? FormatBase.prettyDate(this.dtend_date, "%B %d, %Y %H:%M") : this.dtend);
      return s;
    },
    
    toICalendar: function() {
      return TailsConfig.getFormat("hcalendar").toICalendar([this]);
    },
    
    toVEvent: function(x) {
      // METHOD, X-ORIGINAL-URL, X-WR-CALNAME, PRODID, VERSION
      x.prop(this, "method"        , "PUBLISH"          ).add();
      x.memo(null, "X-ORIGINAL-URL", this.source.url    ).add();
      x.memo(null, "X-WR-CALNAME"  , this.source.title  ).add();
      x.memo(null, 'PRODID'        , TailsConfig.prodId ).add();
      x.memo(null, 'VERSION'       , "2.0"              ).add();
      
      // BEGIN:VEVENT
      x.memo(null, "BEGIN", "VEVENT").add();
      
      // DTSTART, DTEND, LOCATION, URL, SUMMARY, DESCRIPTION,
      // CATEGORIES, CLASS, DTSTAMP, UID, SEQUENCE, STATUS, TRANSP
      x.dateProp ( this, "dtstart"     ).add();
      x.dateProp ( this, "dtend"       ).add();
      x.prop     ( this, "location"    ).utf8().add();
      x.prop     ( this, "url"         ).add();
      x.prop     ( this, "summary"     ).utf8().add();
      x.prop     ( this, "description" ).utf8().add();
      x.commaList( this, "categories"  ).utf8().add();
      x.prop     ( this, "class"       ).utf8().add();
      x.dateProp ( this, "dtstamp"     ).add();
      x.prop     ( this, "uid"         ).add();
      x.prop     ( this, "sequence"    ).add();
      x.prop     ( this, "status"      ).add();
      x.prop     ( this, "transp"      ).add();
      
      // GEO
      x.compList(this.geo, 'latitude', 'longitude').add("GEO");
      
      // ORGANIZER
      x.prop(this.organizer, "email").mailto().add("ORGANIZER");
      
      // ATTENDEE
      var attendee = x.array(this, 'attendees', "email")
          .modProp('role').modProp('partstat').modProp('rsvp');
      attendee.applyToAll(function(){
        if (this.object['delegated-from']
            && this.object['delegated-from'].match(/^mailto:(.*)$/)) {
          this.modifier('DELEGATED-FROM', '"MAILTO:' + RegExp.$1 + '"');
        }
      }, []);
      attendee.mailto().add("ATTENDEE");
      
      // ATTACH
      x.objProp(this, "attach", 'url').fmt('type').add();
      
      // RRULE
      if (this.rrule) {
        var s = '';
        if (this.rrule.freq)
          s += 'FREQ=' + this.rrule.freq;
        if (this.rrule.until)
          s += (s.length > 0 ? ';' : '') + 'UNTIL=' + this.rrule.until;
        if (this.rrule.bydays)
          s += (s.length > 0 ? ';' : '') + 'BYDAY=' + this.rrule.bydays.join(',');
        x.memo(null, 'RRULE', s).add();
      }

      // END:VEVENT
      x.memo(null, "END", "VEVENT").add();
    }
  },
  
  // wrap the given array of hcalendar objects in one VCALENDAR
  toICalendar: function(arr) {
    var lang = arr.length > 0 ? arr[0].source.lang : null;
    var x = new ExportHelper("VCALENDAR", lang);
    for (var i=0; i<arr.length; i++) {
      arr[i].toVEvent(x);
    }
    return x.toString();
  },
  
  _evalUserObject: function(node, object) {
    var url = FormatBase.toURL(node);
    if (url) {
      if (url.match(/^mailto:(.*)$/))
        object.email = RegExp.$1;
      else
        object.url = url;
    } else
      object.value = FormatBase.toText(node);
  },

  end: null
});
